﻿#define _CRT_SECURE_NO_WARNINGS 1


//题目：半有序排序
//给你一个下标从 0 开始、长度为 n 的整数排列 nums 。
//
//如果排列的第一个数字等于 1 且最后一个数字等于 n ，则称其为 半有序排列 。
//你可以执行多次下述操作，直到将 nums 变成一个 半有序排列 ：
//
//选择 nums 中相邻的两个元素，然后交换它们。
//返回使 nums 变成 半有序排列 所需的最小操作次数。
//
//排列 是一个长度为 n 的整数序列，其中包含从 1 到 n 的每个数字恰好一次。



//示例 1：
//
//输入：nums = [2, 1, 4, 3]
//输出：2
//解释：可以依次执行下述操作得到半有序排列：
//1 - 交换下标 0 和下标 1 对应元素。排列变为[1, 2, 4, 3] 。
//2 - 交换下标 2 和下标 3 对应元素。排列变为[1, 2, 3, 4] 。
//可以证明，要让 nums 成为半有序排列，不存在执行操作少于 2 次的方案。
//示例 2：
//
//输入：nums = [2, 4, 1, 3]
//输出：3
//解释：
//可以依次执行下述操作得到半有序排列：
//1 - 交换下标 1 和下标 2 对应元素。排列变为[2, 1, 4, 3] 。
//2 - 交换下标 0 和下标 1 对应元素。排列变为[1, 2, 4, 3] 。
//3 - 交换下标 2 和下标 3 对应元素。排列变为[1, 2, 3, 4] 。
//可以证明，要让 nums 成为半有序排列，不存在执行操作少于 3 次的方案。
//示例 3：
//
//输入：nums = [1, 3, 4, 2, 5]
//输出：0
//解释：这个排列已经是一个半有序排列，无需执行任何操作。
//
//
//提示：
//
//2 <= nums.length == n <= 50
//1 <= nums[i] <= 50
//nums 是一个 排列



//int semiOrderedPermutation(int* nums, int numsSize){
// }


//——————————————————————————————————————————————————————


//个人答案：
//首先想到就是老老实实排序，排一次加一次
//因为“相邻的两个元素”，真的很像冒泡排序
//但是又想想这样并不妥，会有冗余的步骤放在交换非目标元素上
//又想到题目只要求返回次数，没要求返回排序后的数组
//所以根本不需要老老实实排序，只需要推算出次数即可

//个人思路：
//遍历数组，找到1和numsSize所在的位置
//例如：
//*(nums + i) == 1		——需要i次才能将1交换到首位置
//*(numsSize + i) == 1  ——需要（numsSize- 1- i）次才能将numsSize交换到末位置
//还需要考虑特殊情况，1在numsSize的后面
//模拟交换的时候，如果1在numsSize的后面，在交换1的时候就必然会遇到nusSize被交换的情况
//但是实际数组中，numsSize的位置并没有变动，这样次数就会多记一次
//所以还要判断这种特殊情况

//代码：
//int semiOrderedPermutation(int* nums, int numsSize) 
//{
//    int time = 0;
//    int minlocation = 0;
//    int maxlocation = 0;
//    int i = 0;
//    if (*nums != 1 || *(nums + numsSize - 1) != numsSize)
//    {
//        for (i = 0; i < numsSize; i++)
//        {
//            if (*(nums + i) == 1)
//            {
//                minlocation = i;
//                time += i;
//            }
//            if (*(nums + i) == numsSize)
//            {
//                maxlocation = i;
//                time += (numsSize - 1 - i);
//            }
//        }
//        if (minlocation > maxlocation)
//        {
//            time--;
//        }
//    }
//    return time;
//}


//——————————————————————————————————————————————————————


//参考答案：
//方法：模拟
//思路与算法
//
//根据题意我们找到 1 在数组中的索引 first，n 在数组中的索引 last
//此时分为两种情况讨论：
//
//如果 first<last，此时将 1 通过交换相邻元素移到数组的首位需要的交换次数为 first
//将 n 通过交换相邻元素移到数组的末尾需要的交换次数为 n−1−last
//总的交换次数即为 first + n−1−last；
//
//如果 first>last，此时将 1 通过交换相邻元素移到数组的首位需要的交换次数为 first
//将 n 通过交换相邻元素移到数组的末尾需要的交换次数为 n−1−first
//由于 first > last，实际交换过程时 1 与 n 会同时交换 1 次
//因此会减少 1 次交换，总的交换次数即为 first + n−1−last−1。

//代码：
int semiOrderedPermutation(int* nums, int numsSize) {
    int first = 0, last = 0;
    for (int i = 0; i < numsSize; i++) {
        if (nums[i] == 1) {
            first = i;
        }
        if (nums[i] == numsSize) {
            last = i;
        }
    }
    return first + numsSize - 1 - last - (last < first ? 1 : 0);//真妙
}



//题目来源：力扣
//https://leetcode.cn/problems/semi-ordered-permutation/solutions/2999667/ban-you-xu-pai-lie-by-leetcode-solution-9s0r/?envType=daily-question&envId=2024-12-17